package com.corpgovernment.organization.service.budget;

import com.corpgovernment.api.organization.bo.budget.ReleaseBudgetRequestBO;
import com.corpgovernment.api.organization.bo.budget.ReleaseBudgetResponseBO;
import com.corpgovernment.organization.entity.db.budget.BudgetInfoEntity;
import com.corpgovernment.organization.entity.db.budget.BudgetItemEntity;
import com.corpgovernment.organization.entity.db.budget.BudgetOccupancyEntity;
import com.corpgovernment.organization.mapper.budget.BudgetInfoMapper;
import com.corpgovernment.organization.mapper.budget.BudgetItemMapper;
import com.corpgovernment.organization.mapper.budget.BudgetOccupancyMapper;
import com.corpgovernment.organization.mq.MultiTenantBudgetNotifyProducer;
import com.corpgovernment.organization.util.PreCheckUtil;
import com.ctrip.corp.obt.generic.utils.CollectionUtils;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class ReleaseBudgetService extends BaseBudgetService<ReleaseBudgetRequestBO, ReleaseBudgetResponseBO> {

    @Resource
    private BudgetOccupancyMapper budgetOccupancyMapper;

    @Resource
    private BudgetItemMapper budgetItemMapper;

    @Resource
    private BudgetInfoMapper budgetInfoMapper;

    @Resource
    private MultiTenantBudgetNotifyProducer multiTenantBudgetNotifyProducer;

    /**
     * 释放预算
     */
    private ReleaseBudgetResponseBO releaseBudget(ReleaseBudgetRequestBO request) {
        BudgetInfoEntity budgetInfo = budgetInfoMapper.selectByPrimaryKey(request.getBudgetId());
        PreCheckUtil.checkNotNull(budgetInfo, "预算单号错误，没有查询到预算单配置");
        PreCheckUtil.checkArgument(!budgetInfo.getIsDeleted(), "该预算单已不可用，请检查");
        //更新occupancy
        List<BudgetOccupancyEntity> budgetOccupancies = budgetOccupancyMapper.selectByApplyNoAndBudgetId(request.getApplyNo(), request.getBudgetId());
        if (CollectionUtils.isEmpty(budgetOccupancies)) {
            log.warn(String.format("[%s]没有预算占用记录", request.getApplyNo()));
            return ReleaseBudgetResponseBO.success();
        }
        Map<String, BigDecimal> productOccupancyMap = Maps.newHashMap();
        Map<String, BigDecimal> productUsedMap = Maps.newHashMap();
        for (BudgetOccupancyEntity budgetOccupancy : budgetOccupancies) {
            String productType = budgetOccupancy.getProductType();
            productOccupancyMap.put(productType, budgetOccupancy.getAmountOccupy());
            budgetOccupancy.setAmountOccupy(new BigDecimal(0));
            if (!CollectionUtils.isEmpty(request.getProductFeeUsed()) && request.getProductFeeUsed().containsKey(productType)) {
                BigDecimal useFee = request.getProductFeeUsed().get(productType);
                budgetOccupancy.setAmountUsed(budgetOccupancy.getAmountUsed().add(useFee));
                productUsedMap.put(productType, useFee);
            }
        }
        budgetOccupancyMapper.updateBatchSelective(budgetOccupancies);
        //更新item、总预算
        List<BudgetItemEntity> budgetItems = budgetItemMapper.selectByBudgetId(request.getBudgetId());
        BigDecimal feeTotalOccupy = new BigDecimal(0);
        BigDecimal feeTotalUsed = new BigDecimal(0);
        for (BudgetItemEntity budgetItem : budgetItems) {
            BigDecimal feeOccupy = new BigDecimal(0);
            BigDecimal feeUsed = new BigDecimal(0);
            for (String product : budgetItem.getType().split("/")) {
                if (productOccupancyMap.containsKey(product)) {
                    feeOccupy = feeOccupy.add(productOccupancyMap.get(product));
                }
                if (productUsedMap.containsKey(product)) {
                    feeUsed = feeUsed.add(productUsedMap.get(product));
                }
            }
            PreCheckUtil.checkArgument(budgetItem.getAmountOccupy().compareTo(feeOccupy) >= 0, String.format("[%s]预算项[%s]释放失败，金额大小不正确", request.getApplyNo(), budgetItem.getTypeDesc()));
            budgetItem.setAmountOccupy(budgetItem.getAmountOccupy().subtract(feeOccupy));
            budgetItem.setAmountUsed(budgetItem.getAmountUsed().add(feeUsed));
            feeTotalOccupy = feeTotalOccupy.add(feeOccupy);
            feeTotalUsed = feeTotalUsed.add(feeUsed);
        }
        PreCheckUtil.checkArgument(budgetInfo.getAmountOccupy().compareTo(feeTotalOccupy) >= 0, String.format("[%s]预算释放失败，金额大小不正确", request.getApplyNo()));
        budgetInfo.setAmountOccupy(budgetInfo.getAmountOccupy().subtract(feeTotalOccupy));
        budgetInfo.setAmountUsed(budgetInfo.getAmountUsed().add(feeTotalUsed));
        budgetInfoMapper.updateSelective(budgetInfo);
        budgetItemMapper.updateBatchSelective(budgetItems);
        //发送预算阀值告警消息
        multiTenantBudgetNotifyProducer.sendBudgetNotifyMsg(request.getBudgetId());
        return ReleaseBudgetResponseBO.success();
    }

    @Override
    @Transactional
    public ReleaseBudgetResponseBO doOperation(ReleaseBudgetRequestBO request) {
        return releaseBudget(request);
    }
}